package com.zttek.photosShareProject.modules.service.share.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.zttek.photosShareProject.common.json.ImageVO;
import com.zttek.photosShareProject.common.json.ShareVO;
import com.zttek.photosShareProject.common.json.UserVO;
import com.zttek.photosShareProject.common.json.VO;
import com.zttek.photosShareProject.common.myException.DBException;
import com.zttek.photosShareProject.modules.mapper.*;
import com.zttek.photosShareProject.modules.model.*;
import com.zttek.photosShareProject.modules.service.login.IUserService;
import com.zttek.photosShareProject.modules.service.share.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@SuppressWarnings("unchecked")
public class ShareService implements IShareService {

//    @Autowired
//    private IExamineService examineService;

    @Autowired
    private IImageService imageService;

    @Autowired
    private IUserService userService;

    @Autowired
    private IInfoService infoService;

    @Autowired
    private ICommentService commentService;

    @Autowired
    private ShareMapper shareMapper;

    @Autowired
    private HideMapper hideMapper;

    @Autowired
    private CollectMapper collectMapper;

    @Autowired
    private StarMapper starMapper;

    @Autowired
    private SharePraiseMapper praiseMapper;


    @Transactional
    @Override
    public Share newShare(Long[] imagesId, String content, Long[] atIds, Long userId, Long sourceId, boolean hide) throws Exception {
        Share share = new Share();
        Date date = new Date();
        share.setCreateTime(date);
//        share.setUpdateTime(date);
        share.setImages(VO.mergeIds(imagesId));
        share.setUserId(userId);
        share.setDescription(content);
        share.setAtUserIds(VO.mergeIds(atIds));
//        shareUpdate(share);
        share.setSource(sourceId);
        int status = 1;
        if (sourceId != null)
            status |= 8;
        if (hide)
            status |= 2;
        share.setStatus(status);

        shareMapper.insert(share);

        if (atIds != null)
            for (Long atId : atIds) {
                infoService.createUserInfoForShare(atId, userId, share.getId(), IInfoService.AT);
            }
//        examineService.queueShare(share.getId(), date);

        return share;
    }

    @Transactional
    @Override
    public void deleteShare(Long shareId) throws Exception {
//        Share share = shareSelectById(shareId);
        Share share = shareMapper.selectById(shareId);
        share.setValid(0);
        share.setDeleteTime(new Date());
//        shareUpdate(share);
        shareMapper.updateById(share);
    }

    @Override
    public Share selectShare(Long shareId) throws Exception {
//        Share share = shareSelectById(shareId);
        return shareMapper.selectById(shareId);
    }

    @Override
    public List<Share> selectShareByIdList(List<Long> ids) throws Exception {
        EntityWrapper<Share> ew = new EntityWrapper<>();
        ew.where("valid=1").and("(status & 1)=1");
        if (ids.size() > 0) {
            ew.in("id", ids);
        } else {
            ew.and("1 < 1");
        }
        return shareMapper.selectList(ew);
    }

    @Override
    public Page<Share> selectPublicShare(Page<Share> page, Long userId) throws Exception {
        EntityWrapper<Share> ew = new EntityWrapper<>();
        ew.where("valid=1").and("(status & 7)=1");
        List<Long> hideList = getUserHideList(userId);
        if (hideList.size() > 0) {
            ew.notIn("id", hideList);
        }
//        List<Share> list = shareSelectPage(page, ew);
        List<Share> list = shareMapper.selectPage(page, ew);
        page.setRecords(list);
        return page;
    }

    @Override
    public Page<Share> selectSelfShare(Page<Share> page, Long userId) throws Exception {
        EntityWrapper<Share> ew = new EntityWrapper<>();
        ew.where("user_id={0}", userId).and("valid=1");
//        List<Share> list = shareSelectPage(page, ew);
        List<Share> list = shareMapper.selectPage(page, ew);
        page.setRecords(list);
        return page;
    }

    @Override
    public Page<Share> selectHideShare(Page<Share> page, Long userId) throws Exception {
        EntityWrapper<Share> ew = new EntityWrapper<>();
        ew.where("valid=1").and("(status & 7)=1");
        List<Long> hideList = getUserHideList(userId);
        if (hideList.size() > 0) {
            ew.in("id", hideList);
        }
        List<Share> list = shareMapper.selectPage(page, ew);
        page.setRecords(list);
        return page;
    }

    @Override
    public Page<Share> selectCollectShare(Page<Share> page, Long userId) throws Exception {
        EntityWrapper<Share> ew = new EntityWrapper<>();
        ew.where("valid=1").and("(status & 7)=1");
        List<Long> collectList = getUserCollectList(userId);
        if (collectList.size() > 0) {
            ew.in("id", collectList);
        }
        List<Share> list = shareMapper.selectPage(page, ew);
        page.setRecords(list);
        return page;
    }

    @Transactional
    @Override
    public void updatePraiseCount(Long shareId, boolean isPlus) throws Exception {
//        Share share = shareSelectById(shareId);
        Share share = shareMapper.selectById(shareId);
        int i = share.getTotalPraise();
        if (isPlus)
            i++;
        else i--;
        share.setTotalPraise(i);

//        shareUpdate(share);
        shareMapper.updateById(share);
    }

    @Transactional
    @Override
    public void updateCommentCount(Long shareId, boolean isPlus) throws Exception {
//        Share share = shareSelectById(shareId);
        Share share = shareMapper.selectById(shareId);
        int i = share.getTotalComment();
        if (isPlus)
            i++;
        else i--;
        share.setTotalComment(i);

//        shareUpdate(share);
        shareMapper.updateById(share);
    }

    @Override
    public void updateShare(Share share) throws Exception {
        shareMapper.updateById(share);
    }

    @Transactional
    @Override
    public void praise(Long shareId, Long userId, boolean isPlus) throws Exception {
        updatePraiseCount(shareId, isPlus);

        EntityWrapper<SharePraise> ew = new EntityWrapper<>();
        ew.where("share_id={0}", shareId).and("user_id={0}", userId);
        SharePraise sharePraise;
        Date date = new Date();
//        List<SharePraise> list = praiseSelectList(ew);
        List<SharePraise> list = praiseMapper.selectList(ew);
        if (list == null || list.size() == 0) {
            sharePraise = new SharePraise();
            sharePraise.setShareId(shareId);
            sharePraise.setUserId(userId);
            sharePraise.setCreateTime(date);
//            praiseInsert(sharePraise);
            praiseMapper.insert(sharePraise);
        } else {
            sharePraise = list.get(0);
        }

        if (isPlus) {
            sharePraise.setValid(1);

            Share targetShare = selectShare(shareId);
            infoService.createUserInfoForShare(targetShare.getUserId(), userId, shareId, IInfoService.PRAISE);
        } else {
            sharePraise.setValid(0);
            sharePraise.setDeleteTime(date);
        }

//        praiseUpdate(sharePraise);
        praiseMapper.updateById(sharePraise);
    }

    @Override
    public List<Long> getUserPraiseList(Long userId) throws Exception {
        List<Long> list = new ArrayList<>();
        EntityWrapper<SharePraise> ew = new EntityWrapper<>();
        ew.eq("user_id", userId).and("valid = 1");
//        List<SharePraise> sharePraises = praiseSelectList(ew);
        List<SharePraise> sharePraises = praiseMapper.selectList(ew);
        for (SharePraise sharePraise : sharePraises) {
            list.add(sharePraise.getShareId());
        }
        return list;
    }

    @Transactional
    @Override
    public void hide(Long shareId, Long userId, boolean isDo) throws Exception {
        EntityWrapper<Hide> ew = new EntityWrapper<>();
        ew.where("share_id={0}", shareId).and("user_id={0}", userId);
        Hide hide;
        Date date = new Date();
//        List<Hide> list = hideSelectList(ew);
        List<Hide> list = hideMapper.selectList(ew);
        if (list == null || list.size() == 0) {
            hide = new Hide();
            hide.setShareId(shareId);
            hide.setUserId(userId);
            hide.setCreateTime(date);
//            hideInsert(hide);
            hideMapper.insert(hide);
        } else {
            hide = list.get(0);
        }

        if (isDo) {
            hide.setValid(1);
        } else {
            hide.setValid(0);
            hide.setDeleteTime(date);
        }

//        hideUpdate(hide);
        hideMapper.updateById(hide);
    }

    @Override
    public List<Long> getUserHideList(Long userId) throws Exception {
        List<Long> list = new ArrayList<>();
        EntityWrapper<Hide> ew = new EntityWrapper<>();
        ew.eq("user_id", userId).and("valid = 1");
//        List<Hide> hides = hideSelectList(ew);
        List<Hide> hides = hideMapper.selectList(ew);
        for (Hide hide : hides) {
            list.add(hide.getShareId());
        }
        return list;
    }

    @Transactional
    @Override
    public void collect(Long shareId, Long userId, boolean isDo) throws Exception {
        EntityWrapper<Collect> ew = new EntityWrapper<>();
        ew.where("share_id={0}", shareId).and("user_id={0}", userId);
        Collect collect;
        Date date = new Date();
//        List<Collect> list = collectSelectList(ew);
        List<Collect> list = collectMapper.selectList(ew);
        if (list == null || list.size() == 0) {
            collect = new Collect();
            collect.setShareId(shareId);
            collect.setUserId(userId);
            collect.setCreateTime(date);
//            collectInsert(collect);
            collectMapper.insert(collect);
        } else {
            collect = list.get(0);
        }

        if (isDo) {
            collect.setValid(1);

            Share targetShare = selectShare(shareId);
            infoService.createUserInfoForShare(targetShare.getUserId(), userId, shareId, IInfoService.COLLECT);
        } else {
            collect.setValid(0);
            collect.setDeleteTime(date);
        }

//        collectUpdate(collect);
        collectMapper.updateById(collect);
    }

    @Override
    public List<Long> getUserCollectList(Long userId) throws Exception {
        List<Long> list = new ArrayList<>();
        EntityWrapper<Collect> ew = new EntityWrapper<>();
        ew.eq("user_id", userId).and("valid = 1");
//        List<Collect> collects = collectSelectList(ew);
        List<Collect> collects = collectMapper.selectList(ew);
        for (Collect collect : collects) {
            list.add(collect.getShareId());
        }
        return list;
    }

    @Transactional
    @Override
    public void star(Long targetId, Long userId, boolean isDo) throws Exception {
        EntityWrapper<Star> ew = new EntityWrapper<>();
        ew.where("share_id={0}", targetId).and("user_id={0}", userId);
        Star star;
        Date date = new Date();
//        List<Star> list = starSelectList(ew);
        List<Star> list = starMapper.selectList(ew);
        if (list == null || list.size() == 0) {
            star = new Star();
            star.setTargerId(targetId);
            star.setUserId(userId);
            star.setCreateTime(date);
//            starInsert(star);
            starMapper.insert(star);
        } else {
            star = list.get(0);
        }

        if (isDo) {
            star.setValid(1);

            infoService.createUserInfoForNotice(targetId, userId, IInfoService.STAR);
        } else {
            star.setValid(0);
            star.setDeleteTime(date);
        }

//        starUpdate(star);
        starMapper.updateById(star);
    }

    @Override
    public List<Long> getUserStarList(Long userId) throws Exception {
        List<Long> list = new ArrayList<>();
        EntityWrapper<Star> ew = new EntityWrapper<>();
        ew.eq("user_id", userId).and("valid = 1");
//        List<Star> stars = starSelectList(ew);
        List<Star> stars = starMapper.selectList(ew);
        for (Star star : stars) {
            list.add(star.getTargerId());
        }
        return list;
    }

    @Override
    public ShareVO share2VO(Share share, Long userId, boolean fast) throws Exception {
        List<Long> praises = new ArrayList<>(), hides = new ArrayList<>(), collects = new ArrayList<>();
        fillInfomation(praises, hides, collects, userId);
        return share2VO(share, userId, praises.contains(share.getId()), hides.contains(share.getId()),
                collects.contains(share.getId()), fast);
    }

    private ShareVO share2VO(Share share, Long userId, boolean praise, boolean hide, boolean collect, boolean fast) throws Exception {
        User author = userService.selectUserById(share.getUserId());
        List<Image> images = imageService.selectImagesByIds(share.getImages());
        List<ImageVO> list = imageService.image2VO(images, true);
        ImageVO[] imageVOs = new ImageVO[list.size()];
        list.toArray(imageVOs);
        UserVO userVO = userService.user2VO(author, null, true);
        List<Long> praises = new ArrayList<>(), hides = new ArrayList<>(), collects = new ArrayList<>();
        UserVO[] atList = atIds2VOs(share.getAtUserIds());
        ShareVO vo = new ShareVO(share, imageVOs, userVO, praise, hide, collect, atList);
        if (fast) {
            Comment fastComment = commentService.selectFastComment(share.getId());
            if(fastComment != null)
                vo.setFastComment(commentService.comment2VO(fastComment, userId, false));
        }
        return vo;
    }

    @Override
    public List<ShareVO> share2VO(List<Share> shares, Long userId, boolean fast) throws Exception {
        List<ShareVO> list = new ArrayList<>();
        List<Long> praises = new ArrayList<>(), hides = new ArrayList<>(), collects = new ArrayList<>();
        fillInfomation(praises, hides, collects, userId);
        for (Share share : shares) {
            list.add(share2VO(share, userId, praises.contains(share.getId()), hides.contains(share.getId()),
                    collects.contains(share.getId()), fast));
        }
        return list;
    }

    @Override
    public UserVO[] atIds2VOs(String atIds) throws Exception {
        UserVO[] atList = null;
        if (atIds != null) {
            Long[] ids = VO.divideLongIds(atIds);
            List<User> ul = userService.selectUserByIds(ids);
            List<UserVO> uvl = userService.user2VO(ul, null, false);
            atList = new UserVO[uvl.size()];
            uvl.toArray(atList);
        }
        return atList;
    }

    @Override
    public UserVO[] atIds2VOs(List<Long> atIds) throws Exception {
        if (atIds == null)
            return null;
        UserVO[] atList = null;
        Long[] ls = new Long[atIds.size()];
        List<User> ul = userService.selectUserByIds(atIds.toArray(ls));
        List<UserVO> uvl = userService.user2VO(ul, null, false);
        atList = new UserVO[uvl.size()];
        uvl.toArray(atList);
        return atList;
    }

    private void fillInfomation(List<Long> praises, List<Long> hides, List<Long> collects, Long userId) throws Exception {
        if (userId == null)
            return;
        praises.addAll(getUserPraiseList(userId));
        hides.addAll(getUserHideList(userId));
        collects.addAll(getUserCollectList(userId));
    }

    @Deprecated
    private Share shareSelectById(long shareId) {
        Share share = null;
        try {
            share = shareMapper.selectById(shareId);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.SHARE_SELECT_FAILURE);
        }
        return share;
    }

    @Deprecated
    private void shareInsert(Share share) {
        try {
            shareMapper.insert(share);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.SHARE_INSERT_FAILURE);
        }
    }

    @Deprecated
    private List<Share> shareSelectPage(Page<Share> page, EntityWrapper<Share> ew) {
        List<Share> list = null;
        try {
            list = shareMapper.selectPage(page, ew);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.SHARE_SELECT_FAILURE);
        }
        return list;
    }

    @Deprecated
    private void shareUpdate(Share share) {
        try {
            shareMapper.updateById(share);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.SHARE_UPDATE_FAILURE);
        }
    }

    @Deprecated
    private List<SharePraise> praiseSelectList(EntityWrapper<SharePraise> ew) {
        List<SharePraise> sharePraises = null;
        try {
            praiseMapper.selectList(ew);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.PRAISE_SELECT_FAILURE);
        }
        return sharePraises;
    }

    @Deprecated
    private void praiseInsert(SharePraise sharePraise) {
        try {
            praiseMapper.insert(sharePraise);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.PRAISE_INSERT_FAILURE);
        }
    }

    @Deprecated
    private void praiseUpdate(SharePraise sharePraise) {
        try {
            praiseMapper.updateById(sharePraise);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.PRAISE_UPDATE_FAILURE);
        }
    }

    @Deprecated
    private List<Hide> hideSelectList(EntityWrapper<Hide> ew) {
        List<Hide> hides = null;
        try {
            hides = hideMapper.selectList(ew);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.HIDE_SELECT_FAILURE);
        }
        return hides;
    }

    @Deprecated
    private void hideInsert(Hide hide) {
        try {
            hideMapper.insert(hide);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.HIDE_INSERT_FAILURE);
        }
    }

    @Deprecated
    private void hideUpdate(Hide hide) {
        try {
            hideMapper.updateById(hide);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.HIDE_UPDATE_FAILURE);
        }
    }

    @Deprecated
    private List<Collect> collectSelectList(EntityWrapper<Collect> ew) {
        List<Collect> collects = null;
        try {
            collects = collectMapper.selectList(ew);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.COLLECT_SELECT_FAILURE);
        }
        return collects;
    }

    @Deprecated
    private void collectInsert(Collect collect) {
        try {
            collectMapper.insert(collect);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.COLLECT_INSERT_FAILURE);
        }
    }

    @Deprecated
    private void collectUpdate(Collect collect) {
        try {
            collectMapper.updateById(collect);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.COLLECT_UPDATE_FAILURE);
        }
    }

    @Deprecated
    private List<Star> starSelectList(EntityWrapper<Star> ew) {
        List<Star> stars = null;
        try {
            stars = starMapper.selectList(ew);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.STAR_SELECT_FAILURE);
        }
        return stars;
    }

    @Deprecated
    private void starInsert(Star star) {
        try {
            starMapper.insert(star);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.STAR_INSERT_FAILURE);
        }
    }

    @Deprecated
    private void starUpdate(Star star) {
        try {
            starMapper.updateById(star);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DBException(DBException.STAR_UPDATE_FAILURE);
        }
    }
}
